﻿namespace ZeroSum.Extensions;

/// <summary>
///     基类型<see cref="Object" />扩展辅助操作类
/// </summary>
public static class ObjectExtensions
{
    #region 公共方法

    /// <summary>
    ///     把对象类型转换为指定类型
    /// </summary>
    /// <param name="value"></param>
    /// <param name="conversionType"></param>
    /// <returns></returns>
    public static object? CastTo(this object? value, Type conversionType)
    {
        if (conversionType.IsNullableType()) conversionType = conversionType.GetUnNullableType();
        if (conversionType.IsEnum) return Enum.Parse(conversionType, value?.ToString() ?? string.Empty);

        return conversionType == typeof(Guid)
            ? Guid.Parse(value?.ToString() ?? string.Empty)
            : Convert.ChangeType(value, conversionType);
    }

    /// <summary>
    ///     把对象类型转化为指定类型
    /// </summary>
    /// <typeparam name="T"> 动态类型 </typeparam>
    /// <param name="value"> 要转化的源对象 </param>
    /// <returns> 转化后的指定类型的对象，转化失败引发异常。 </returns>
    public static T? CastTo<T>(this object? value)
    {
        if (value == null && default(T) == null) return default;
        if (value?.GetType() == typeof(T))
            return (T) value;
        var result = CastTo(value, typeof(T));
        return (T) result!;
    }

    /// <summary>
    ///     把对象类型转化为指定类型，转化失败时返回指定的默认值
    /// </summary>
    /// <typeparam name="T"> 动态类型 </typeparam>
    /// <param name="value"> 要转化的源对象 </param>
    /// <param name="defaultValue"> 转化失败返回的指定默认值 </param>
    /// <returns> 转化后的指定类型对象，转化失败时返回指定的默认值 </returns>
    public static T? CastTo<T>(this object? value, T? defaultValue)
    {
        try
        {
            return CastTo<T>(value);
        }
        catch (Exception)
        {
            return defaultValue;
        }
    }

    /// <summary>
    ///     判断当前值是否介于指定范围内
    /// </summary>
    /// <typeparam name="T"> 动态类型 </typeparam>
    /// <param name="value"> 动态类型对象 </param>
    /// <param name="start"> 范围起点 </param>
    /// <param name="end"> 范围终点 </param>
    /// <param name="leftEqual"> 是否可等于上限（默认等于） </param>
    /// <param name="rightEqual"> 是否可等于下限（默认等于） </param>
    /// <returns> 是否介于 </returns>
    public static bool IsBetween<T>(this IComparable<T> value, T start, T end, bool leftEqual = true,
        bool rightEqual = true) where T : IComparable
    {
        var flag = leftEqual ? value.CompareTo(start) >= 0 : value.CompareTo(start) > 0;
        return flag && (rightEqual ? value.CompareTo(end) <= 0 : value.CompareTo(end) < 0);
    }

    #endregion
}